package base.keyboard
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.utils.getTimer;
	
	import utils.ArrayUtil;
	import utils.DisplayUtil;

	/**
	 * 组合键类
	 */	
	public class KeyCombo extends EventDispatcher
	{
		/**
		 *组合键之间的间隔时间 
		 */		
		private var _idle:uint;
		private var _type:String;
		
		/**
		 *正在被按下的键 
		 */
		private var _downKeys:Vector.<uint>=new Vector.<uint>();
		
		/**
		 *已经被按下的键(该集为有效的按组合键间隔时间按下的键)
		 */		
		private var _downComboKeys:Vector.<uint>=new Vector.<uint>();
		
		/**
		 *组合键里的键值都已经被按下组合键列表 
		 */		
		private var _downCombos:Vector.<KeyComboCell>=new Vector.<KeyComboCell>();
		
		/**
		 *组合键列表 
		 */		
		private var _keyCombos:Vector.<KeyComboCell>=new Vector.<KeyComboCell>();
		
		/**
		 * 最长的组合键长度
		 */		
		private var _maxComboLength:uint=0;
		
		
		/**
		 *上一次键按下的时间(毫秒) 
		 */		
		private var _previousKeyDownTime:uint;
		/**
		 *是否激活当前组合键 
		 */
		private var _isAction:Boolean=true;
		
		/**
		 * 组合键
		 * @param type 类型名称
		 * @param idle 组合键之间的间隔时间(毫秒)，当值为0时即无时间限制
		 */
		public function KeyCombo(type:String, idle:uint = 0, isAction:Boolean=true)
		{
			_type=type;
			_idle = idle;
			_isAction=isAction;
			
			if(_isAction)
			{
				KeyboardFactory.Instance.addEventListener(KeyEvent.KEY_DOWN, __onKeyDown);
				KeyboardFactory.Instance.addEventListener(KeyEvent.KEY_UP, __onKeyUp);
				KeyboardFactory.Instance.addEventListener(Event.DEACTIVATE, __onDeactivate);	
			}
		}
		
		/**
		 * 添加组合键
		 * @param keyComboCell 组合键
		 */		
		public function addKeyCombo(keyComboCell:KeyComboCell):void
		{
			var len:uint = _keyCombos.length;
			if(_keyCombos.indexOf(keyComboCell)>-1) return;
			
			_maxComboLength = Math.max(_maxComboLength, keyComboCell.length);
			_keyCombos.push(keyComboCell);//增加至组合键列表
		}
		
		/**
		 * 移除组合键
		 * @param keyComboCell 组合键
		 */		
		public function removeKeyCombo(keyComboCell:KeyComboCell):void
		{
			var i:int = -1;
			var len:uint = _keyCombos.length;
			if(_keyCombos.indexOf(keyComboCell)!=-1)_keyCombos.splice(_keyCombos.indexOf(keyComboCell), 1);
			
			if (_maxComboLength == keyComboCell.length)
			{
				_maxComboLength = 0;
				for each(var item:KeyComboCell in _keyCombos)
				{
					_maxComboLength = Math.max(_maxComboLength, item.length);
				}
			}
			keyComboCell.dispose();
			keyComboCell=null;
		}
		
		/**
		 * 移除组合键
		 * @param keyCodes 键值列表
		 */		
		public function removeKeyComboByKeys(keyCodes:Array):void
		{
			var keyComboCell:KeyComboCell=getKeyCombo(keyCodes);
			removeKeyCombo(keyComboCell);
		}
		
		/**
		 * 移除组合键
		 * @param keyCodes 键值列表
		 */		
		public function removeKeyComboByName(name:String):void
		{
			var keyComboCell:KeyComboCell=getKeyComboByName(name);
			removeKeyCombo(keyComboCell);
		}
		
		/**
		 * 取得组合键
		 * @param keyCodes 键值列表
		 */
		public function getKeyCombo(keyCodes:Array):KeyComboCell
		{
			for each(var item:KeyComboCell in _keyCombos)
			{
				if(ArrayUtil.equals(item.keyCodes, keyCodes))
				{
					return item;
					break;
				}
			}
			return null;
		}
		
		/**
		 * 取得组合键
		 * @param keyCodes 键值列表
		 */
		public function getKeyComboByName(name:String):KeyComboCell
		{
			for each(var item:KeyComboCell in _keyCombos)
			{
				if(item.name==name)
				{
					return item;
					break;
				}
			}
			return null;
		}
		
		public function keyComboExistByName(name:String):Boolean
		{
			for each(var item:KeyComboCell in _keyCombos)
			{
				if(item.name==name)
				{
					return true;
					break;
				}
			}
			return false;
		}
		
		/**
		 *当键盘有键被按下 
		 * @param evt
		 * 
		 */		
		private function __onKeyDown(evt:KeyEvent):void
		{
			if(!_isAction)return;
			if(!_keyCombos || _keyCombos.length<=0) return;
			var keyCode:uint = evt.data;
			var alreadyDown:Boolean = isDown(keyCode);//_downKeys[keyCode];//取得当前键值是否在之前已经被按下了
			if(alreadyDown) return;
			_downKeys.push(keyCode);
			
			//如果按键间隔时间超出有效间隔值(_idle),则将已经被按下的有效键列表清除
			if (getTimer() - _previousKeyDownTime > _idle) _downComboKeys.length = 0;
			
			_downComboKeys.push(keyCode);//增加至合法的按下键列表
			
			//如果按下的键列表长度大于最大组合键长度，则将列表前的键删除
			if (_downComboKeys.length > _maxComboLength) _downComboKeys.shift();
			
			matchKeyCombo();
			
			_previousKeyDownTime = getTimer();
		}
		
		/**
		 * 遍历当前的有效的按下键列表是否与单项的组合键匹配
		 * 
		 */		
		private function matchKeyCombo():void
		{
			//遍历当前的有效的按下键列表是否与单项的组合键匹配
			for each(var item:KeyComboCell in _keyCombos)
			{
				if(!item.isAction)continue;
				isComboKey(item);//执行匹配检查
				isComboIsKeyAllDown(item);//执行组合键的所有键是否被按下检查
			}
		}
		
		/**
		 * 当键盘有键被弹起
		 * @param evt
		 * 
		 */		
		private function __onKeyUp(evt:KeyEvent):void
		{
			if(!_isAction)return;
			if(_keyCombos.length<=0) return;
			
			var keyCode:uint = evt.data;
			delDownKey(keyCode);//删除已按住的键
			
			//遍历组合键里的键值都已经被按下组合键列表，释放相应的组合键
			for each(var item:KeyComboCell in _downCombos)
			{
				if (item.hasKey(keyCode))
				{
					if(_downCombos.indexOf(item)!=-1)_downCombos.splice(_downCombos.indexOf(item), 1);
					dispatchEvent(new KeyEvent(KeyEvent.COMBO_ALL_KEY_DOWN_RELEASE, item));
				}
				isSingleKey(item);
			}
			
//			matchKeyCombo();
		}
		
		// 系统失去焦点。
		private function __onDeactivate(event:Event):void
		{
			if(!_isAction)return;
			if(_keyCombos.length<=0) return;
			
			for each(var item:KeyComboCell in _downCombos)
			{
				dispatchEvent(new KeyEvent(KeyEvent.COMBO_ALL_KEY_DOWN_RELEASE, item));
			}
			
			_downKeys.length=0;
			while(_downCombos && _downCombos.length)
			{
				_downCombos.shift();
			}
			_downComboKeys.length = 0;
		}
		
		private function isSingleKey(keyComboCell:KeyComboCell):void
		{
			var cellKeys:Vector.<uint> = _downKeys.slice(-keyComboCell.length);
			if (ArrayUtil.equals(keyComboCell.keyCodes, cellKeys))
			{
				dispatchEvent(new KeyEvent(KeyEvent.COMBO_ACTION, keyComboCell));
			}
		}
		
		/**
		 *指定的组合键中的键值是否存在于已经被按下过的键列表中，即表示该组合键被激活 
		 * @param keyComboCell 要检查的组合键
		 * 
		 */		
		private function isComboKey(keyComboCell:KeyComboCell):void
		{
			var cellKeys:Vector.<uint> = _downComboKeys.slice(-keyComboCell.length);
			if (ArrayUtil.equals(keyComboCell.keyCodes, cellKeys))
			{
				dispatchEvent(new KeyEvent(KeyEvent.COMBO_ACTION, keyComboCell));
			}
		}
		
		/**
		 * 在有效的组合键间隔时间内检查指定的组合键里面所有的键值是否被按下
		 * @param keyComboCell 单项组合键
		 * 
		 */		
		private function isComboIsKeyAllDown(keyComboCell:KeyComboCell):void
		{
			for each(var code:uint in keyComboCell.keyCodes)
			{
				if (!isDown(code))
				{
					return;
				}
			}

			_downCombos.push(keyComboCell);
			dispatchEvent(new KeyEvent(KeyEvent.COMBO_ALL_KEY_DOWN, keyComboCell));
		}
		
		/**
		 * 指定的键值是否正在被按下
		 * @param keyCode 键值
		 * @return
		 */		
		public function isDown(keyCode:uint):Boolean
		{
			return _downKeys.indexOf(keyCode)>-1;
		}
		

		public function delDownKey(keyCode:uint):void
		{
			if(_downKeys.indexOf(keyCode)!=-1)_downKeys.splice(_downKeys.indexOf(keyCode),1);
		}
		
		/**
		 *当前是否存在组合键被激活 
		 * @return 
		 * 
		 */		
		public function get isExistComboAction():Boolean
		{
			//遍历当前的有效的按下键列表是否与单项的组合键匹配
			for each(var item:KeyComboCell in _keyCombos)
			{
				var cellKeys:Vector.<uint> = _downComboKeys.slice(-item.length);
				if (ArrayUtil.equals(item.keyCodes, cellKeys))
				{
					return true;
				}
			}
			
			return false;
		}
		
		/**
		 * 资源释放
		 */		
		public function dispose():void
		{
			KeyboardFactory.Instance.removeEventListener(KeyEvent.KEY_DOWN, __onKeyDown);
			KeyboardFactory.Instance.removeEventListener(KeyEvent.KEY_UP, __onKeyUp);
			KeyboardFactory.Instance.removeEventListener(Event.DEACTIVATE, __onDeactivate);
			
			_downKeys.length=0;
			_downKeys = null;
			_downComboKeys.length = 0;
			_downComboKeys = null;
			while(_downCombos && _downCombos.length>0)
			{
				DisplayUtil.dispose(_downCombos.shift());
			}
			_downCombos = null;
			while(_keyCombos && _keyCombos.length>0)
			{
				DisplayUtil.dispose(_keyCombos.shift());
			}
			_keyCombos = null;
		}

		public function get type():String
		{
			return _type;
		}

		public function set type(value:String):void
		{
			_type = value;
		}

		/**
		 *是否激活当前组合键 
		 */
		public function get isAction():Boolean
		{
			return _isAction;
		}

		/**
		 * @private
		 */
		public function set isAction(value:Boolean):void
		{
			_isAction = value;
		}
	}
}